import com.asnike.P.bejeweled.*;
import com.greensock.TweenMax;

private function fillBlanks():void{
	TweenMax.delayedCall( _model.jewelRemoveDuration, function():void{
		fillBlankAsExistJewels();
	} );
	TweenMax.delayedCall( _model.jewelRemoveDuration*2, function():void{
		fillBlankAsNewJewels();
	} );
	
}
private function fillBlankAsExistJewels():void{
	var i:int, j:int, map:Array, result:*;
	
	map = getMap();
	for( i = 0, j = map.length ; i < j ; ++i ){
		result = getFillsAndBlanks( map, i );
		moveExistJewelToBlanks( result, i );
	}
}
private function fillBlankAsNewJewels():void{
	var i:int, j:int, map:Array, result:*, lastIndexX:int;
	
	map = getMap();
	lastIndexX = findOutLastJewelIndexX();
	for( i = 0, j = map.length ; i < j ; ++i ){
		result = getBlanks( map, i );
		moveNewJewelToBlanks( result, i, isLastIndexX( lastIndexX, i ) );
		if( isLastIndexX( lastIndexX, i ) ){
			return;
		}
	}
}
private function findOutLastJewelIndexX():int{
	var i:int, j:int, map:Array, temp:Array, result:int;
	
	map = getMap();
	for( i = 0, j = map.length ; i < j ; ++i ){
		temp = getBlanks( map, i );
		if( temp.length > 0 ){
			result = i;
		}
	}
	
	return result;
}
private function isLastIndexX( $lastIndexX:int, $target:int ):Boolean{
	return $lastIndexX === $target;
}
private function getFillsAndBlanks( $map:Array, $indexY:int ):Object{
	var i:int, j:int, result:Object;
	
	result = {jewels:[], fills:[], blanks:[]};
	for( i = 0, j = $map[$indexY].length ; i < j ; ++i ){
		if( isFill( $map[i][$indexY] ) ){
			result.jewels[result.jewels.length] = $map[i][$indexY];
			result.fills[result.fills.length] = i;
		}
		if( isBlank( $map[i][$indexY] ) ){
			result.blanks[result.blanks.length] = i;
		}
	}
	return result;
}
private function isFill( $target:Jewel ):Boolean{
	return !isBlank( $target );
}
private function isBlank( $target:Jewel ):Boolean{
	return $target === null;
}
private function moveExistJewelToBlanks( $data:Object, $indexY:int ):void{
	var moveData:Object;
	
	moveData = getMoveAmounts( $data.fills, $data.blanks );
	moveJewelsInModel( $data.jewels, moveData.indices, $indexY );
	moveJewelsInView( $data.jewels, moveData.amounts );
}
private function getMoveAmounts( $fills:Array, $blanks:Array ):Object{
	var i:int, j:int, k:int, l:int, blankIndex:int, result:Object, amount:int;
	
	result = {indices:{original:[], target:[]}, amounts:[]};
	
	for( i = 0, j = $fills.length ; i < j ; ++i ){
		for( k = 0, l = $blanks.length ; k < l ; ++k ){
			if( hasToMove( $fills[i], $blanks[blankIndex], $blanks.length ) ){
				amount = $blanks.length - blankIndex;
				result.indices.original[result.indices.original.length] = $fills[i];
				result.indices.target[result.indices.target.length] = $fills[i] + amount;
				result.amounts[result.amounts.length] = amount;
				break;
			}else{
				++blankIndex;
			}
		}
	}
	return result;
}
private function hasToMove( $value1:int, $value2:int, $blanksLength:int ):Boolean{
	return $value1 < $value2 && $blanksLength > 0;
}
private function moveJewelsInModel( $jewels:Array, $indices:Object, $indexY:int ):void{
	var i:int, j:int, jewelIndex:int, map:Array;
	
	map = getMap();
	for( i = 0, j = map[0].length ; i < j ; ++i ){
		if( $indices.original.indexOf( i ) > -1 ){
			map[i][$indexY] = null;
		}
		if( $indices.target.indexOf( i ) > -1 ){
			map[i][$indexY] = $jewels[jewelIndex++];
		}
	}
}
private function moveJewelsInView( $jewels:Array, $amounts:Array ):void{
	var i:int, j:int;
	
	for( i = 0, j = $amounts.length ; i < j ; ++i ){
		moveDownToJewel( $jewels[i], $amounts[i] );
	}
}
private function moveDownToJewel( $target:Jewel, $amount:int, $endFunction:Function = null ):void{
	_view.moveDownToJewel( $target, $amount, $endFunction );
}

private function getBlanks( $map:Array, $indexY:int ):Array{
	var i:int, j:int, result:Array;
	
	result = [];
	for( i = 0, j = $map[$indexY].length ; i < j ; ++i ){
		if( isBlank( $map[i][$indexY] ) ){
			result[result.length] = i;
		}
	}
	return result;
}
private function moveNewJewelToBlanks( $data:Array, $indexY:int, $isLast:Boolean ):void{
	var i:int, j:int, jewelIndex:int, map:Array;
	
	map = getMap();
	for( i = 0, j = $data.length ; i < j ; ++i ){
		map[$data[i]][$indexY] = getMovingJewel( GameModel.TOTAL_JEWEL_TYPE*Math.random(), $indexY*Jewel.WIDTH + Jewel.WIDTH*.5, $data[i]*Jewel.HEIGHT + Jewel.HEIGHT*.5 - $data.length*Jewel.HEIGHT, $data.length, JEWEL_CLICK, ( $isLast && i + 1 === j  ) );
	}
	
}



//---------------------------------------------------------------------------------------------------------------------------------------------------
private function debugMap():void{
	var i:int, j:int, map:Array;
	
	map = getMap();
	trace( '----------------------------------------------' );
	for( i = 0, j = map.length ; i < j ; ++i ){
		trace( i + 'line -> ' +  getJewelsType( map[i] ) );
	}
	trace( '----------------------------------------------' );
}
private function getJewelsType( $line:Array ):Array{
	var i:int, j:int, result:Array;
	
	result = [];
	for( i = 0, j = $line.length ; i < j ; ++i ){
		if( $line[i] === null ){
			result[result.length] = 'e';
		}else{
			result[result.length] = $line[i].getType();
		}
	}
	
	return result;
}